package org.mzy.basic.service.impl;

import org.apache.commons.lang3.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.mzy.basic.config.BussinessException;
import org.mzy.basic.constant.BaseConstants;
import org.mzy.basic.dto.EmailCodeDto;
import org.mzy.basic.dto.PhoneSmsCodeDto;
import org.mzy.basic.service.IVerifyCodeService;
import org.mzy.basic.util.EmailUtil;
import org.mzy.basic.util.SendSmsUtil;
import org.mzy.basic.util.StrUtils;
import org.mzy.basic.util.VerifyCodeUtils;
import org.mzy.user.domain.User;
import org.mzy.user.mapper.LogininfoMapper;
import org.mzy.user.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
@Slf4j
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private LogininfoMapper logininfoMapper;


    /**
     * 获取图形验证码
     *
     * @param uuidKey
     * @return
     */
    @Override
    public String getImageCode(String uuidKey) {
        // 生成随机数
        String randomCode = StrUtils.getComplexRandomString(4);
        // 存入到reids
        redisTemplate.opsForValue().set(uuidKey, randomCode, 3, TimeUnit.MINUTES);
        // 生成图形验证码返回给前端
        return VerifyCodeUtils.VerifyCode(100, 35, randomCode);
    }

    /**
     * 发送邮箱验证码
     *
     * @param dto
     */
    @Override
    public void emailCode(EmailCodeDto dto) {
        // 验证参数是否为空,EmailCodeDto中已经判断
        // 验证邮箱格式、图形验证码是否正确、当前邮箱是否已经注册
        this.verifyEmailCode(dto);
        // 两次发送短信间隔是否大于60s
        this.sendEmailCode(String.format(BaseConstants.VerfityCodeCons.REGISTER_SMSCODE_PHONE, dto.getEmail()));
    }

    /**
     * 发送手机验证码
     *
     * @param dto
     */
    @Override
    public void smsCode(PhoneSmsCodeDto dto) {
        // 如果type的值为register，则
        if ("register".equals(dto.getType())) {
            // 验证参数是否为空
            if (StringUtils.isBlank(dto.getPhone())) {
                throw new BussinessException("手机号不能为空！");
            }
            if (StringUtils.isBlank(dto.getImageCodeKey())) {
                throw new BussinessException("图形验证码不能为空！");
            }
            if (StringUtils.isBlank(dto.getImageCodeValue())) {
                throw new BussinessException("图形验证码不能为空！");
            }
            // 验证手机号格式是否正确、验证图形验证码是否正确、手机号是否注册的方法
            this.verifyImgageCode(dto);
            // 两次发送短信间隔是否大于60s
            this.sendSmsCode(String.format(BaseConstants.VerfityCodeCons.REGISTER_SMSCODE_PHONE, dto.getPhone()));
            // 如果type的值为binder，则
        } else if ("binder".equals(dto.getType())) {
            this.sendSmsCode(String.format(BaseConstants.VerfityCodeCons.BINDER_SMSCODE_PHONE, dto.getPhone()));
        }
    }

    @Override
    public void smsCode2(PhoneSmsCodeDto dto) {
        // 验证参数是否为空
        if (StringUtils.isBlank(dto.getPhone())) {
            throw new BussinessException("手机号不能为空！");
        }
        if (StringUtils.isBlank(dto.getImageCodeKey())) {
            throw new BussinessException("图形验证码不能为空！");
        }
        if (StringUtils.isBlank(dto.getImageCodeValue())) {
            throw new BussinessException("图形验证码不能为空！");
        }
        // 验证手机号格式
        if (dto.getPhone().length() != 11) {
            throw new BussinessException("请输入正确的手机号！");
        } else {
            String regex = "^((13[0-9])|(15[^4])|(18[0,2,3,5-9])|(17[0-8])|(147))\\d{8}$";
            boolean isMatch = Pattern.compile(regex).matcher(dto.getPhone()).matches();
            if (!isMatch) {
                throw new BussinessException("请输入正确的手机号！");
            }
        }
        // 图形验证码是否正确
        String imageCode = (String) redisTemplate.opsForValue().get(dto.getImageCodeKey());
        if (StringUtils.isBlank(imageCode) || !imageCode.equalsIgnoreCase(dto.getImageCodeValue())) {
            throw new BussinessException("图形验证码错误！");
        }
        //当前手机号是否已经注册了
        User user = userMapper.findByPhone(dto.getPhone());
        if (null != user) {
            // 两次发送短信间隔是否大于60s
            this.sendSmsCode(String.format(BaseConstants.VerfityCodeCons.REGISTER_SMSCODE_PHONE, dto.getPhone()));
        }
    }

    /*验证手机号格式是否正确、验证图形验证码是否正确、手机号是否注册的方法*/
    private void verifyImgageCode(PhoneSmsCodeDto dto) {
        // 如果手机号的长度不等于11，则抛异常
        if (dto.getPhone().length() != 11) {
            throw new BussinessException("请输入正确的手机号");
        } else {
            // 如果手机号格式不对，也抛异常
            String regex = "^((13[0-9])|(15[^4])|(18[0,2,3,5-9])|(17[0-8])|(147))\\d{8}$";
            boolean isMatch = Pattern.compile(regex).matcher(dto.getPhone()).matches();
            if (!isMatch) {
                throw new BussinessException("请输入正确的手机号！");
            }
        }
        // 获取key（dto.getImageCodeKey()）对应的值
        String imageCode = (String) redisTemplate.opsForValue().get(dto.getImageCodeKey());
        // 如果imageCode为空或者 （不区分大小写的） imageCode的值和dto.getImageCodeValue()不同，那么抛异常
        if (StringUtils.isBlank(imageCode) || !imageCode.equalsIgnoreCase(dto.getImageCodeValue())) {
            throw new BussinessException("图形验证码错误");
        }
        // 调用根据phone查询的方法
        User user = userMapper.findByPhone(dto.getPhone());
        // 如果user已存在，抛异常
        if (null != user) {
            throw new BussinessException("该手机号已被注册");
        }
    }

    /*验证邮箱格式是否正确、验证图形验证码是否正确、邮箱是否注册的方法*/
    private void verifyEmailCode(EmailCodeDto dto) {
        // 验证邮箱格式
        this.verifyEmailFormat(dto);
        // 图形验证码是否正确
        String imageCode = (String) redisTemplate.opsForValue().get(dto.getImageCodeKey());
        if (StringUtils.isBlank(imageCode) || !imageCode.equalsIgnoreCase(dto.getImageCodeValue())) {
            throw new BussinessException("图形验证码错误！");
        }
        // 当前邮箱是否已经注册了
        User user = userMapper.findByEamil(dto.getEmail());
        if (null != user) {
            throw new BussinessException("该邮箱已被注册！");
        }
    }

    /*两次发短信的时间是否大于60秒*/
    private void sendSmsCode(String redisKey) {
        // redis中 key：register:smscode:phone  value：验证码:时间戳
        // 获取key：redisKey 对应的值
        String redisSmsCode = (String) redisTemplate.opsForValue().get(redisKey);
        // 声明一个smsCode为空字符串
        String smsCode = "";
        // 如果redisSmsCode的值不为空或者长度不为0时
        if (StringUtils.isNotBlank(redisSmsCode)) {
            // 将字符串redisSmsCode通过:分割成数组，保存到split
            String[] split = redisSmsCode.split(":");
            // 将split中下标为零的字符串赋值给smsCode
            smsCode = split[0];
            // 获取当前时间
            long newTime = System.currentTimeMillis();
            // 获取reids中的时间,传入redis中的时间戳
            Long oldTime = Long.valueOf(split[1]);
            // 如果当前时间减去reids中的时间小于60秒，则抛异常
            if (newTime - oldTime < 60 * 1000) {
                throw new BussinessException("请稍后再试");
            }
        } else {
            // 如果redisSmsCode的值为空或者长度不0时，则生成新的验证码赋值给smsCode
            smsCode = StrUtils.getRandomString(4);
        }
        // 打印日志：
        log.info("验证码为：{}", smsCode);
        // 声明一个字符串，验证码:当前时间
        String redisValue = smsCode + ":" + System.currentTimeMillis();
        // 将改变后的参数存入reids中
        redisTemplate.opsForValue().set(redisKey, redisValue, 5, TimeUnit.MINUTES);
        // 发送短信
//        SendSmsUtil.send(dto.getPhone(),"你好：你的验证码为："+smsCode+"，5分钟内有效！");
    }

    /*两次发邮箱的时间是否大于60秒*/
    private void sendEmailCode(String redisKey) {
        // redis中 key：register:smscode:phone  value：验证码:时间戳
        String redisEmailCode = (String) redisTemplate.opsForValue().get(redisKey);
        String emailCode = "";
        if (StringUtils.isNotBlank(redisEmailCode)) {
            // 不为空才做 60s校验  redisSmsCode 存的是 验证码:时间戳
            String[] split = redisEmailCode.split(":");
            emailCode = split[0];
            // 当前时间
            long newTime = System.currentTimeMillis();
            // reids中的时间
            long oldTime = Long.valueOf(split[1]);
            if (newTime - oldTime < 60 * 1000) {
                throw new BussinessException("请稍后再试");
            }
        } else {
            // 生成验证码
            emailCode = StrUtils.getRandomString(4);
        }
        log.info("验证码为：{}", emailCode);
        String redisValue = emailCode + ":" + System.currentTimeMillis();
        // 存入到reids
        redisTemplate.opsForValue().set(redisKey, redisValue, 5, TimeUnit.MINUTES);
        // 发送邮箱
        // 发送邮件 邮件内容的连接是激活链接
        String text = "<h1>审核通过，您的验证吗为</h1> " +
                "<h2>" + emailCode + "</h2> ";
        EmailUtil.sendEmail("宠物乐园审核结果", text, "1071937734@qq.com");
    }

    // 验证邮箱格式方法
    public void verifyEmailFormat(EmailCodeDto dto) {
        String regex = "\\w+@(\\w+\\.){1,3}\\w+";
        boolean isMatch = Pattern.compile(regex).matcher(dto.getEmail()).matches();
        if (!isMatch) {
            throw new BussinessException("请输入正确的邮箱");
        }
    }
}